/**
 * Copyright 2021 Huawei Technologies Co., Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "buffer_pool.h"
#include "definitions.h"
namespace ge {
BufferPool::BufferPool(size_t capability) : capability_(capability) {
  data_ = std::unique_ptr<uint8_t>(new (std::nothrow) uint8_t[capability_]);
}
BufferPool::BufferPool() : BufferPool(4096) {}
PoolOffset BufferPool::AddBuffer(const void *buf, size_t len) {
  if (buf == nullptr) {
    return kInvalidOffset;
  }
  if (capability_ - len_ < len) {
    if (Expand(len) != SUCCESS) {
      return kInvalidOffset;
    }
  }
  auto ret = memcpy_s(data_.get() + len_, capability_ - len_, buf, len);
  if (ret != E_OK) {
    return kInvalidOffset;
  }

  auto offset = len_;
  len_ += len;
  return offset;
}
Status BufferPool::Expand(size_t add_len) {
  if (len_ + add_len < add_len) {
    return FAILED;
  }
  size_t new_len = std::max(capability_ * 2, len_ + add_len);
  auto new_data = std::unique_ptr<uint8_t>(new (std::nothrow) uint8_t[new_len]);
  if (new_data == nullptr) {
    return FAILED;
  }
  auto ret = memcpy_s(new_data.get(), new_len, data_.get(), len_);
  if (ret != E_OK) {
    return FAILED;
  }
  data_.swap(new_data);
  capability_ = new_len;
  return SUCCESS;
}
void *BufferPool::GetBase() const {
  return data_.get();
}
size_t BufferPool::GetLen() const {
  return len_;
}
size_t BufferPool::GetCapability() const {
  return capability_;
}
void *BufferPool::GetBuffer(PoolOffset offset) {
  if (offset >= len_) {
    // log error
    return nullptr;
  }
  return data_.get() + offset;
}
Status BufferPool::Resize(size_t new_size) {
  data_.reset(new (std::nothrow) uint8_t[new_size]);
  return SUCCESS;
}
BufferPool &BufferPool::operator=(BufferPool &&other) noexcept {
  data_.swap(other.data_);
  capability_ = other.capability_;
  len_ = other.len_;
  other.Reset();

  return *this;
}
void BufferPool::Reset() {
  len_ = 0;
  capability_ = 0;
  data_ = nullptr;
}
void BufferPool::Swap(BufferPool &other) noexcept {
  data_.swap(other.data_);
  std::swap(len_, other.len_);
  std::swap(capability_, other.capability_);
}
}  // namespace ge
